package com.hpin.mlxteacher.mqtt;

import android.content.Context;
import android.content.SharedPreferences;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hpin.mlxteacher.bean.MessageBean;
import com.hpin.mlxteacher.bean.MqttServiceBean;
import com.hpin.mlxteacher.bean.TopicBean;
import com.hpin.mlxteacher.db.DatabaseManager;
import com.hpin.mlxteacher.mqttsource.MqttClient;
import com.hpin.mlxteacher.mqttsource.MqttConnectOptions;
import com.hpin.mlxteacher.mqttsource.MqttException;
import com.hpin.mlxteacher.mqttsource.MqttTopic;
import com.hpin.mlxteacher.mqttsource.persist.MemoryPersistence;
import com.hpin.mlxteacher.utils.Constant;
import com.hpin.mlxteacher.utils.File2Code;
import com.hpin.mlxteacher.utils.HttpUtil;

import java.util.HashMap;
import java.util.Map;

import de.greenrobot.event.EventBus;

/**
 * mqtt连接管理类
 * <p/>
 * Created by Aaron on 15/12/15.
 */
public class MqttManager {

    private MqttClient mqttClient;

    private Context context;

    private static MqttManager mqttManager = new MqttManager();
    private SharedPreferences sp;
    private MqttMessageCallBack callBack;

    private MqttManager() {
    }

    public static MqttManager getInstance() {
        return mqttManager;
    }

    public MqttClient getMqttClient() {
        return mqttClient;
    }


    /**
     * 获取mqtt的ip和端口号
     */
    public void getMqttIp(Context ctx) {

        this.context = ctx;

        if (sp == null)
            sp = ctx.getSharedPreferences(Constant.CONFIG, Context.MODE_PRIVATE);

        JSONObject j = new JSONObject();
        j.put("token", sp.getString(Constant.token, ""));
        HttpUtil.setPostNoWaring(ctx, Constant.WEB_ROOT_TALK + Constant.TALK_LOGIN, j.toJSONString(), "LOGIN",
                new HttpUtil.SuccessListener() {
                    @Override
                    public void setOnSuccessListener(String str) {

                        try {

                            MqttServiceBean serviceBean = JSONObject.parseObject(str, MqttServiceBean.class);

                            if (serviceBean.code == Constant.SUCCESS) {

                                SharedPreferences.Editor edit = sp.edit();
                                //保存mqtt IP
                                edit.putString(Constant.MQTTIP, serviceBean.ip);
                                edit.putString(Constant.MQTTPORT, serviceBean.port);

                                Constant.topicMap = new HashMap<>();

                                if (serviceBean.topicList != null && serviceBean.topicList.size() > 0) {

                                    Constant.TOPICS = new String[serviceBean.topicList.size()];

                                    for (int i = 0; i < serviceBean.topicList.size(); i++) {
                                        Constant.TOPICS[i] = serviceBean.topicList.get(i).topic;
                                        Constant.topicMap.put(serviceBean.topicList.get(i).topic, serviceBean.topicList.get(i));

                                    }

                                }

                                edit.putString(Constant.TOPIC_MAP, JSON.toJSONString(Constant.topicMap, true));//保存到sp中,防止内存中的被销毁
                                edit.apply();

                                //连接mqtt
                                new Thread(new Runnable() {
                                    @Override
                                    public void run() {
                                        connectMqtt();
                                    }
                                }).start();

//                                LogUtil.e("tag", "HomeActivity : 获取mqtt ip, 端口 成功");

                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    }
                }, null);

    }

    /**
     * 连接MQTT服务器
     * <p/>
     * 聊天的登录名称是用户的手机号,密码是token
     * clientid 是 保存的 用户的id即 userId
     * <p/>
     * //     * @param handlerMessage 连接成功后的需要处理的消息(比如发送消息的时候发现连接断开了,重新连接时需要发送的消息)
     */
    public void connectMqtt() {
//    public void connectMqtt(Context ctx) {

        try {

            if (mqttClient != null && mqttClient.isConnected())
                return;

            mqttClient = new MqttClient(
                    "tcp://" + sp.getString(Constant.MQTTIP, "") + ":" + sp.getString(Constant.MQTTPORT, "")
                    , sp.getString(Constant.phoneNum, ""), new MemoryPersistence());

            //创建一个连接对象
            MqttConnectOptions options = new MqttConnectOptions();
            // mqtt receive offline message若设为false，MQTT服务器将持久化客户端会话的主体订阅和ACK位置，默认为true。
            options.setCleanSession(false);
//            options.setSSLProperties();
            //设置超时时间
            options.setConnectionTimeout(10 * 1000);
            //设置会话心跳时间 单位为秒
            // 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线，但这个方法并没有重连的机制
            options.setKeepAliveInterval(20);
//设置最终端口的通知消息 :设置“遗嘱”消息的话题，若客户端与服务器之间的连接意外中断，服务器将发布客户端的“遗嘱”消息。
            //设置“遗嘱”消息的内容，默认是长度为零的消息。
            //设置“遗嘱”消息的QoS，默认为QoS.ATMOSTONCE。
            //若想要在发布“遗嘱”消息时拥有retain选项，则为true
//            options.setWill("will", );
//            options.setWill("LastWillTopic", "the client will stop !".getBytes(), 0, false);
            options.setUserName(sp.getString(Constant.phoneNum, ""));
            options.setPassword(sp.getString(Constant.token, "").toCharArray());
//            mqttClient.log.isLoggable(Log.DEBUG);
            //创建客户端MQTT回调类
            if (callBack == null)
                callBack = new MqttMessageCallBack(context);
            //设置MQTT回调
            mqttClient.setCallback(callBack);

            mqttClient.connect(options);
//            LogUtil.e("tag", getClass().getName() + "是否连接上了 : " + mqttClient.isConnected());

            if (!mqttClient.isConnected())
                return;

            if (Constant.TOPICS != null && Constant.TOPICS.length > 0)
                mqttClient.subscribe(Constant.TOPICS);

//            LogUtil.e("tag", getClass().getName() + " ========== 成功 ==========");

//            //连接成功获取历史聊天记录
//            getOffLineChatMsg();

        } catch (MqttException e) {
            e.printStackTrace();

        }

    }

    /**
     * 发送聊天内容
     *
     * @param mb    发送的内容
     * @param topic 聊天的主题topic
     */
    public void setMessage(String topic, MessageBean mb) throws Exception {

        if (mqttClient == null || !mqttClient.isConnected()) {
            throw new Exception(Constant.MQTTNOTCONNECT);
        }

        MqttTopic sendTopic = mqttClient.getTopic(topic);

        try {

//            MqttDeliveryToken publish =
            sendTopic.publish(getSendMsg(mb).getBytes(), Constant.MQTT_QOS_ONE, false);
//                    sendTopic.publish(getSendMsg(mb).getBytes(), Constant.MQTT_QOS_ONCE, true);

            if (Constant.OFF_GROUP.equals(mb.operationStyle)) {
                return; //退出群后发送的消息就不要再存储到数据库了
            }

            //保存聊天记录到数据库
            save2DataBase(mb);

            mb.operationStyle = Constant.RECEIVE_MESSAGE;
            EventBus.getDefault().post(mb); //通知fragment页面有新消息

//            int messageId = publish.getMessageId();
//            LogUtil.e("tag", " 消息的Id : " + messageId);

        } catch (MqttException e) {

            Toast.makeText(context, "发送失败!", Toast.LENGTH_SHORT).show();

            e.printStackTrace();
        }
    }

    /**
     * 把发送的时候 无需的字段 置空
     *
     * @param mb
     */
    private String getSendMsg(MessageBean mb) throws Exception {

//        org.json.JSONObject
        JSONObject j = new JSONObject();

        j.put("sendPic", mb.sendPic);
        j.put("sendName", mb.sendName);
        j.put("sendId", mb.sendId);
        j.put("messageType", mb.messageType);

        if (mb.voiceLength < 1)
            mb.voiceLength = 1;
        else if (mb.voiceLength > 60)
            mb.voiceLength = 60;

        j.put("voiceLength", mb.voiceLength);
//            j.put("voiceLength", (int) mb.voiceLength);
//            j.put("voiceLength", (int) mb.voiceLength + "");

//        j.put("chatType", mb.chatType);
        j.put("sendDate", mb.sendDate + "");//改为字符串 配合IOS

        switch (mb.messageType) {

            case Constant.MQTTMESSAGETEXT://文字

                j.put("content", mb.content);

                break;

            case Constant.MQTTMESSAGEPHOTO://图片

                j.put("content", mb.qiniuPath);

                break;
            case Constant.MQTTMESSAGEVOICE://语音

                //把文件路径转成base64的字符串
                j.put("content", File2Code.encodeBase64File(mb.content));

                break;

            case Constant.MQTTMESSAGENOTICE:

                j.put("receivePic", mb.receivePic);
                j.put("receiveName", mb.receiveName);
                j.put("content", mb.content);

                break;

        }

        return j.toJSONString();

    }

    /**
     * 保存数据到数据库
     *
     * @param mb
     */
    private void save2DataBase(MessageBean mb) {

//        sendId VARCHAR, sendName VARCHAR, sendPic VARCHAR," +
//        "receiverTime VARCHAR, isRead VARCHAR, content VARCHAR, topic VARCHAR, messageType VARCHAR" +
//                ", receiveId VARCHAR, receiveName VARCHAR, receivePic VARCHAR, voiceLength VARCHAR, chatType VARCHAR, sendTime VARCHAR)"
        //保存到history表
        DatabaseManager.getInstance().insertHisData(context, new Object[]{mb.sendId, mb.sendName, mb.sendPic, mb.sendDate,
                0, mb.content, mb.channelId, mb.messageType, mb.receiveId, mb.receiveName, mb.receivePic,
                mb.voiceLength, mb.chatType, mb.sendDate, sp.getString(Constant.phoneNum, ""), Constant.LISTENERED});

        //保存到topic表

        //                    topicName, sendId, sendName, sendPic, receiverTime, receiveId" +
//                ",content ,messageType,voiceLength,chatType,sendTime,receivePic, receiveName, isListener, isRead, topic, userId
        DatabaseManager.getInstance().updateTopic(context, new String[]{mb.receiveName, mb.sendId, mb.sendName,
                mb.sendPic, mb.sendDate + "", mb.receiveId, mb.content, mb.messageType,
                mb.voiceLength + "", mb.chatType + "", mb.sendDate + "", mb.receivePic,
                mb.receiveName, Constant.LISTENERED + "", "0", mb.channelId, sp.getString(Constant.phoneNum, "")});

    }

    /**
     * 订阅主题
     *
     * @param topic
     */
    public void subTopicSingle(String topic) {

        if (mqttClient != null && mqttClient.isConnected()) {
            try {

                mqttClient.timeToWait = 500;//要把 timeToWait 的值改变 不知道为什么....
                mqttClient.subscribe(topic, Constant.MQTT_QOS_ONE);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 取消订阅主题
     *
     * @param topic
     */
    public void unSubTopic(String topic) {

        if (mqttClient != null && mqttClient.isConnected()) {
            try {

                mqttClient.timeToWait = 500;//要把 timeToWait 的值改变 不知道为什么....
                mqttClient.unsubscribe(topic);

                removeSpTopic(topic);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 清除sp中的topic
     *
     * @param mTopic
     */
    private void removeSpTopic(String mTopic) {

        //sp中该topic清掉
        if (Constant.topicMap == null)
            Constant.topicMap = (Map<String, TopicBean>) JSON.parse(sp.getString(Constant.TOPIC_MAP, ""));

        if (Constant.topicMap != null) {
            Constant.topicMap.remove(mTopic);
        }

        Map<String, TopicBean> spMap = (Map<String, TopicBean>) JSON.parse(sp.getString(Constant.TOPIC_MAP, ""));
        if (spMap != null) {
            spMap.remove(mTopic);
            sp.edit().putString(Constant.TOPIC_MAP, JSON.toJSONString(spMap, true)).apply();
        }

    }
}